package com.hjq.mallsearch.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.hjq.common.entity.es.SkuEsModel;
import com.hjq.common.utils.R;
import com.hjq.mallsearch.constant.EsConstants;
import com.hjq.mallsearch.feign.ProducrFeign;
import com.hjq.mallsearch.service.ResultSearchService;
import com.hjq.mallsearch.vo.AttrRespVO;
import com.hjq.mallsearch.vo.BrandEntityVO;
import com.hjq.mallsearch.vo.SearchParamVO;
import com.hjq.mallsearch.vo.SearchResponseVO;
import com.mysql.cj.util.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @auther HJQ
 */
@Service
public class ResultSearchServiceImpl implements ResultSearchService {
    @Autowired
    RestHighLevelClient client;
    @Autowired
    ProducrFeign productFeign;
    /**
     *
     * @param searchParam
     * @return SearchResponseVO
     */
    @Override
    public SearchResponseVO search(SearchParamVO searchParam) {
        //准备执行请求
        SearchRequest searchRequest = buildSearchRequest(searchParam);
        SearchResponse searchResponse = null;
        //执行请求
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //返回数据
        SearchResponseVO searchResult = getSearchResult(searchResponse,searchParam);
        return searchResult;
    }

    private SearchResponseVO  getSearchResult(SearchResponse searchResponse,SearchParamVO searchParam) {
        SearchResponseVO result = new SearchResponseVO();
        //1.返回所有查询到的商品
        SearchHits hits = searchResponse.getHits();
        if (hits.getHits() != null && hits.getHits().length > 0) {
            List<SkuEsModel> skuEsModels = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                SkuEsModel skuEsModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
                HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");
                if (skuTitle != null) {
                    Text[] fragments = skuTitle.getFragments();

                    String string = fragments[0].toString();

                    skuEsModel.setSkuTitle(string);
                }

                skuEsModels.add(skuEsModel);


            }
            result.setProducts(skuEsModels);
        }


        //2.当前商品的属性星系
        List<SearchResponseVO.AttrVO> attrVOs = new ArrayList<>();
        ParsedNested attrAgg = searchResponse.getAggregations().get("attrAgg");
        ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attrIdAgg");
        List<? extends Terms.Bucket> attrIdAggBuckets = attrIdAgg.getBuckets();
        for (Terms.Bucket attrIdAggBucket : attrIdAggBuckets) {
            SearchResponseVO.AttrVO attrVO = new SearchResponseVO.AttrVO();
            //attrId
            long attrId = attrIdAggBucket.getKeyAsNumber().longValue();
            attrVO.setAttrId(attrId);
            //attrName
            ParsedStringTerms attrNameAgg = attrIdAggBucket.getAggregations().get("attrNameAgg");
            String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
            attrVO.setAttrName(attrName);
            //attrVal
            ParsedStringTerms attrValAgg = attrIdAggBucket.getAggregations().get("attrValAgg");
            List<String> attrVals = attrValAgg.getBuckets().stream().map(MultiBucketsAggregation.Bucket::getKeyAsString
            ).collect(Collectors.toList());
            attrVO.setAttrValue(attrVals);
            //只要参数传过来了，他就不要显示了
            //searchParam.getAttrs().add(attrId);
            attrVOs.add(attrVO);

        }

        result.setAttrs(attrVOs);

        //3.当前商品涉及的品牌
        List<SearchResponseVO.BrandVO> brandVOS = new ArrayList<>();
        ParsedLongTerms brandAgg = searchResponse.getAggregations().get("brandAgg");
        List<? extends Terms.Bucket> brandAggBuckets = brandAgg.getBuckets();
        for (Terms.Bucket brandAggBucket : brandAggBuckets) {
            //brandId
            SearchResponseVO.BrandVO brandVO = new SearchResponseVO.BrandVO();
            long brandId = brandAggBucket.getKeyAsNumber().longValue();
            brandVO.setBrandId(brandId);
            //brandName
            ParsedStringTerms brandNameAgg = brandAggBucket.getAggregations().get("brandNameAgg");
            String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
            brandVO.setBrandName(brandName);
            //brandImg
            ParsedStringTerms brandImgAgg = brandAggBucket.getAggregations().get("brandImgAgg");
            String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();
            brandVO.setBrandImg(brandImg);
            brandVOS.add(brandVO);
        }
        result.setBrands(brandVOS);
        //4.当前商品设计的所有分类信息
        List<SearchResponseVO.CatalogVO> catalogVOList = new ArrayList<>();
        ParsedLongTerms catAgg = searchResponse.getAggregations().get("catAgg");
        List<? extends Terms.Bucket> buckets = catAgg.getBuckets();
        for (Terms.Bucket bucket : buckets) {
            SearchResponseVO.CatalogVO catalogVO = new SearchResponseVO.CatalogVO();
            //可能会出问题
            String keyAsString = bucket.getKeyAsString();
            //设置分类的Id
            catalogVO.setCatalogId(Long.parseLong(keyAsString));
            //基于id统计的名字
            ParsedStringTerms catNameAgg = bucket.getAggregations().get("catNameAgg");
            String catName = catNameAgg.getBuckets().get(0).getKeyAsString();
            catalogVO.setCatalogName(catName);
            catalogVOList.add(catalogVO);
        }
        result.setCatalogs(catalogVOList);
        //分页信息-页码
        result.setPageNum(searchParam.getPageNum());
        //分类信息-总记录数
        long totalHits = hits.getTotalHits().value;
        result.setTotal(totalHits);
        //分类信息-总页码
        int totolPage = (int) totalHits % EsConstants.PRODUCT_PAGESIZE == 0 ? (int) totalHits / EsConstants.PRODUCT_PAGESIZE : (int) totalHits / EsConstants.PRODUCT_PAGESIZE + 1;
        result.setTotalPages(totolPage);
        //pageNav信息
        List<Integer> pageNav = new ArrayList<>();
        int fromPage = Math.max(result.getPageNum() - 2, 1);
        int endPage = Math.min(result.getPageNum() + 2, totolPage);
        for (int i = fromPage; i <= endPage; i++) {
            pageNav.add(i);

        }
        result.setPageNavs(pageNav);


        //面包屑导航信息

        List<String> attrs = searchParam.getAttrs();
        if (attrs != null && attrs.size() >= 1) {
            List<SearchResponseVO.NavVO> navVOS = attrs.stream().map(attr -> {
                SearchResponseVO.NavVO navVO = new SearchResponseVO.NavVO();
                String[] split = attr.split("_");
                navVO.setNavValue(split[1]);
                R info = productFeign.info(Long.parseLong(split[0]));
                result.getAttrIds().add(Long.parseLong(split[0]));
                if (info.getCode() == 0) {
                    String s = JSON.toJSONString(info.get("attr"));
                    AttrRespVO attrRespVO = JSON.parseObject(s, AttrRespVO.class);
                    navVO.setNavName(attrRespVO.getAttrName());
                } else {
                    navVO.setNavName(split[0]);
                }
                String replacedParamAttr= replaceParamString(searchParam, attr, "attrs");
                String link = "http://search.hjqmall.com/list.html?" + replacedParamAttr;
                String nlink = link.replace("?&", "?");
                navVO.setLink(nlink);

                return navVO;
            }).collect(Collectors.toList());
            result.setNavs(navVOS);
        }
        //品牌和分类的面包屑导航
        if (searchParam.getBrandId() != null && searchParam.getBrandId().size() > 0) {
            List<SearchResponseVO.NavVO> navs = result.getNavs();
            SearchResponseVO.NavVO navVO = new SearchResponseVO.NavVO();
            R brandInfos = productFeign.brandInfos(searchParam.getBrandId());

            if (brandInfos.getCode() == 0) {
                String s = JSON.toJSONString(brandInfos.get("brand"));
                List<BrandEntityVO> brandEntityVOS = JSON.parseObject(s, new TypeReference<List<BrandEntityVO>>() {
                });
                StringBuffer buffer = new StringBuffer();
                String replaceOfBrand="";
                for (BrandEntityVO brandEntityVO : brandEntityVOS) {
                    buffer.append(brandEntityVO.getName() + ";");
                     replaceOfBrand=replaceParamString(searchParam,brandEntityVO.getBrandId()+"","brandId");

                }
                navVO.setNavValue(buffer.toString());
                String linkOfBrand = "http://search.hjqmall.com/list.html?" + replaceOfBrand;
                String nlinkOfBrand = linkOfBrand.replace("?&", "?");
                navVO.setLink( nlinkOfBrand);
            }
            navs.add(navVO);
        }
        //TODO 分类，不需要剔除



            return result;
        }


    private String replaceParamString(SearchParamVO searchParam, String value,String key) {
        String encode=value;
        try {
            encode = URLEncoder.encode(value, "UTF-8");
            encode=encode.replace("+","%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String replace = searchParam.get_queryString().replace("&"+key+"=" + encode, "");
        String replace1 = replace.replace(key+"=" + encode, "");

        return replace1;
    }

    private SearchRequest buildSearchRequest(SearchParamVO searchParam) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//构建DSL语句
        //模糊匹配，过滤
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //1.1 must
        if(!StringUtils.isNullOrEmpty(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle", searchParam.getKeyword()));

        }
        //1.2 filter;
        if(searchParam.getCatalog3Id()!=null){
            //3级分类
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));

        }
        if(searchParam.getBrandId()!=null&&searchParam.getBrandId().size()>0){
            //品牌id
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }

        List<String> attrs = searchParam.getAttrs();
        if(attrs !=null&& attrs.size()>0){
            // 属性查询

            for (String attrStr : attrs) {
                //attr=1_5存：2cun
                String[] s = attrStr.split("_");
                //属性id
                String attrId = s[0];
                //属性id
                String[] attrVal = s[1].split(":");
                //每一个id都要产生nestedQuery
                BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
                nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrVal));
                NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
                boolQueryBuilder.filter(nestedQueryBuilder);
            }
        }
        //是否有库存
        if(searchParam.getHasStock()!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock",searchParam.getHasStock()==1));
        }


        //是否价格区间
        String skuPrice = searchParam.getSkuPrice();
        if(!StringUtils.isNullOrEmpty(skuPrice)){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("skuPrice");
            String[] s = skuPrice.split("_");
            if(s.length==2){
                //区间
                rangeQueryBuilder.gte(s[0]).lte(s[1]);
            }else if (s.length<=1){
                //有最大值
                if(skuPrice.startsWith("_")){
                    rangeQueryBuilder.lte(s[0]);
                }
                if(skuPrice.endsWith("_")){
                    rangeQueryBuilder.gte(s[0]);
                }

            }
            boolQueryBuilder.filter(rangeQueryBuilder);
        }




        sourceBuilder.query(boolQueryBuilder);

        //排序聚合高亮
        //2.1paixu
        String sort = searchParam.getSort();
        if(!StringUtils.isNullOrEmpty(sort)){
            String[] s = sort.split("_");
            SortOrder order=s[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC;
            sourceBuilder.sort(s[0], order);
        }
        //2.2 页码
        sourceBuilder.from((searchParam.getPageNum()-1)*EsConstants.PRODUCT_PAGESIZE);
        sourceBuilder.size(EsConstants.PRODUCT_PAGESIZE);


        //2.3 高亮
        if(!StringUtils.isNullOrEmpty(searchParam.getKeyword())){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("skuTitle").preTags("<b style='color:red'>").postTags("</b>");
            sourceBuilder.highlighter(highlightBuilder);
        }


        //2.4 聚合分析
        TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brandAgg");
        brandAgg.field("brandId").size(50);
        //平拍聚合的子聚合
        brandAgg.subAggregation(AggregationBuilders.terms("brandNameAgg").field("brandName").size(1));
        brandAgg.subAggregation(AggregationBuilders.terms("brandImgAgg").field("brandImg").size(1));
        sourceBuilder.aggregation(brandAgg);
        //分类聚合
        TermsAggregationBuilder catAgg = AggregationBuilders.terms("catAgg").field("catalogId").size(20);
        catAgg.subAggregation(AggregationBuilders.terms("catNameAgg").field("catalogName").size(1));
        sourceBuilder.aggregation(catAgg);
        //属性聚合
        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg","attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId").size(10);
        attrAgg.subAggregation(attrIdAgg);
        //聚合分析AttrName,和所有attrValue
        attrIdAgg.subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName").size(1));
        attrIdAgg.subAggregation(AggregationBuilders.terms("attrValAgg").field("attrs.attrValue").size(20));

        sourceBuilder.aggregation(attrAgg);
        System.out.println("DSL:"+sourceBuilder.toString());
        SearchRequest searchRequest = new SearchRequest(new String[]{EsConstants.PRODUCT_INDEX},sourceBuilder);
        return searchRequest;

    }
}
